// Cell names have been changed in this file by netl_namemap on Mon Jan  3 04:00:14 UTC 2022
////////////////////////////////////////////////////////////////////////////// 
//
//  pcs_raw_lane_fsm.v
//
//  Per-lane fsm to read and execute instructions stored in the common memory
//
//  Original Author: Ameer Youssef 
//  Current Owner: Ameer Youssef   
//
////////////////////////////////////////////////////////////////////////////// 
//
// Copyright (C) 2013 Synopsys, Inc.  All rights reserved.
//
// SYNOPSYS CONFIDENTIAL - This is an unpublished, proprietary work of
// Synopsys, Inc., and is fully protected under copyright and trade secret
// laws.  You may not view, use, disclose, copy, or distribute this file or
// any information contained herein except pursuant to a valid written
// license agreement. It may not be used, reproduced, or disclosed to others
// except in accordance with the terms and conditions of that agreement.
//
////////////////////////////////////////////////////////////////////////////// 
//
//    Perforce Information
//    $Author: ameer $
//    $File: //dwh/up16/main/dev/pcs_raw/dig/rtl/pcs_raw_lane_fsm.v $
//    $DateTime: 2016/02/17 20:31:07 $
//    $Revision: #40 $
//
////////////////////////////////////////////////////////////////////////////// 

`include "dwc_e12mp_phy_x4_ns_macros.v"
`include "dwc_e12mp_phy_x4_ns_cr_macros.v"
`include "dwc_e12mp_phy_x4_ns_pcs_raw_macros.v"

`timescale 1ns/10fs
module dwc_e12mp_phy_x4_ns_pcs_raw_lane_fsm (
// Clocks and resets
input  wire          cr_clk,
input  wire          cr_rst,
input  wire          fsm_rst,

// Interrupt request
input  wire          irq,
  
// Interrupt mask clear
output reg           irq_msk_clr,

// Control/status signals
input  wire [1:0]    rx_adapt_sts_i,
input  wire [3:0]    cr_chan_addr,

// Fast flags (from aon_lane register)
input  wire          rx_fast_vco_cal_r,
input  wire          rx_fast_vco_wait_r,
input  wire          rx_fast_pwrup_r,
input  wire          tx_fast_rxdet_r,
input  wire          tx_fast_cmn_mode_r,
input  wire          tx_fast_sup_r,
input  wire          rx_fast_dfe_adapt_r,
input  wire          rx_fast_afe_adapt_r,
input  wire          rx_fast_iq_cal_r,
input  wire          rx_fast_reflvl_cal_r,
input  wire          rx_fast_bypass_cal_r,
input  wire          rx_fast_dfe_cal_r,
input  wire          rx_fast_afe_cal_r,
input  wire          rx_fast_adapt_r,
input  wire          rx_fast_startup_cal_r,

// Mantis 6746 - Mission mode adaptation registers
input  wire [6:0]    rx_fast_flags_rsvd_r,
input  wire          rx_fast_cont_afe_cal_r,
input  wire          rx_fast_cont_phase_cal_r,
input  wire          rx_fast_cont_data_cal_r,
input  wire          rx_fast_cont_adapt_r,
input  wire          rx_fast_cont_cal_adapt_r,

// Common calibration status
input  wire          lanes_cmncal_init,
input  wire          lanes_cmncal_done,

`ifdef DWC_E12MP_X4NS_SRAM_SUPPORT
// SRAM bypass signal to know where to read FW from
input  wire          sram_bypass,
`endif

// CREG interface output to Memory-Aribter
input  wire          cr_mem_ack,
input  wire [15:0]   cr_mem_rd_data,
output wire          cr_mem_req,
output wire [15:0]   cr_mem_addr,
output wire [15:0]   cr_mem_wr_data,
output wire          cr_mem_wr_en,
output wire          cr_mem_rd_en,

// CREG interface output to Register-Aribter
input  wire          cr_reg_ack,
input  wire [15:0]   cr_reg_rd_data,
output wire          cr_reg_req,
output wire [15:0]   cr_reg_addr,
output wire          cr_reg_wr_en,
output wire [15:0]   cr_reg_wr_data,
output wire          cr_reg_rd_en,

// CREG interface (accessing CREGs in this block)                     
output wire [15:0]   cr_rd_data,
input  wire [15:0]   cr_wr_data,
input  wire          cr_wr_en,
input  wire [31:0]   cr_sel,

input  wire          scan_mode_i,
input  wire          scan_set_rst_i
);

// -------------------------
// Registers and nets
// -------------------------

reg  [4:0]  curr_state;
reg  [4:0]  next_state;
reg         mem_req;
reg         reg_req;
reg         reg_wr_en;
reg         reg_rd_en;
reg         mem_req_nxt;
reg         reg_req_nxt;
reg         reg_wr_en_nxt;
reg         reg_rd_en_nxt;
reg         maddr_ld;
reg         maddr_inc;
reg         raddr_ld;
reg         wr_data_ld;
reg         wait_ld;
reg         cmd_rdy;
reg  [15:0] opreg_en;
reg  [4:0]  opreg_data_sel;
reg  [15:0] opreg_data_preshf;
wire [31:0] opreg_data_32b;
wire [15:0] opreg_data;
reg  [15:0] fsm_ld_data;
reg         sgnd;
reg         shiftr;
reg  [3:0]  shiftv;
wire        alu_ovflw;
reg         alu_sub;
reg  [4:0]  alu_ipa_sel;
reg  [4:0]  alu_ipb_sel;
reg  [15:0] alu_ipa;
reg  [15:0] alu_ipb;
wire [16:0] alures_nxt; //17 bits

wire        stat_done_pulse;
wire        adapt_done_pulse;
reg  [15:0] reg_rd_data_xtrct;
wire [15:0] reg_rd_data_xtrct_and;
wire [15:0] opreg_data_wrmsk;
reg  [15:0] opreg_data_wrmsk_shft;
wire [3:0]  chan_field;

genvar i;

// CREGs
wire        fsm_ovrd_en_r;
wire        fsm_cmd_start_r;
wire [11:0] fsm_jmp_addr_r;
wire        fsm_jmp_en_r;

// Internal instruction registers
reg  [15:0] ireg;
    
// Registers for output
reg  [11:0] maddr;
reg  [10:0] raddr;
reg  [15:0] wr_data;
wire [4:0]  rx_iq_phase_offset_r;

// Wait counter
reg  [26:0] wait_cnt;

// Operational registers
reg  [15:0] r0;
reg  [15:0] r1;
reg  [15:0] r2;
reg  [15:0] r3;
reg  [15:0] r4;
reg  [15:0] r5;
reg  [15:0] r6;
reg  [15:0] r7;
reg  [15:0] v0;
reg  [15:0] v1;
reg  [15:0] v2;
reg  [15:0] v3;
reg  [15:0] rega;
reg  [16:0] alures; //17 bits (MSB is overflow bit)
reg  [15:0] rdmsk;
reg  [15:0] wrmsk;

// Mantis 7158 - Synchronize CR reg input to lane_fsm
reg  [15:0] cr_reg_rd_data_d;
reg   [4:0] cr_reg_rd_ack_d;
wire [15:0] cr_reg_rd_data_sync;
wire        cr_reg_rd_ack;
wire        cr_reg_wr_ack;
wire        cr_reg_ack_sync;

// Opreg data select
localparam SEL_R0              = 5'd0;  //
localparam SEL_R1              = 5'd1;  //
localparam SEL_R2              = 5'd2;  //
localparam SEL_R3              = 5'd3;  //
localparam SEL_R4              = 5'd4;  //
localparam SEL_R5              = 5'd5;  //
localparam SEL_R6              = 5'd6;  //
localparam SEL_R7              = 5'd7;  // 16 OPREGS
localparam SEL_V0              = 5'd8;  //
localparam SEL_V1              = 5'd9;  //
localparam SEL_V2              = 5'd10; //
localparam SEL_V3              = 5'd11; //
localparam SEL_REGA            = 5'd12; //
localparam SEL_ALURES          = 5'd13; //
localparam SEL_RDMSK           = 5'd14; //
localparam SEL_WRMSK           = 5'd15; //
localparam SEL_FSM_DATA        = 5'd16;
localparam SEL_IREG            = 5'd17;
localparam SEL_ALURES_NXT      = 5'd18;
localparam SEL_MEM_RDATA       = 5'd19;
localparam SEL_REG_RDATA       = 5'd20;
localparam SEL_REG_RDATA_XTRCT = 5'd21;

// Start of main program in memory
// Default main program is stored in ROM0
localparam MEM_START_ADDR = {4'b000,3'b000,5'b0000}; // 12 bits

// FSM states
localparam IDLE            = 5'd0;
localparam CMD_FETCH       = 5'd1;
localparam CMD_DECODE      = 5'd2;
localparam WAIT_REG_ACK    = 5'd3;
localparam ST_D_1          = 5'd4;
localparam WRMSK_1         = 5'd5;
localparam CP_RA_1         = 5'd6;
localparam CP_RP_1         = 5'd7;
localparam CP_PX_1         = 5'd8;
localparam ADD_1           = 5'd9;
localparam ADD_2           = 5'd10;
localparam STAT_START_1    = 5'd11;
localparam STAT_START_2    = 5'd12;
localparam STAT_WAIT_DN    = 5'd13;
localparam STAT_OPR_1      = 5'd14;
localparam STAT_CORR_1     = 5'd15;
localparam STAT_CORR_2     = 5'd16;
localparam STAT_CORR_3     = 5'd17;
localparam STAT_CORR_4     = 5'd18;
localparam STAT_CORR_5     = 5'd19;
localparam STAT_ESL_RD     = 5'd20;
localparam STAT_RST_MSK    = 5'd21;
localparam STAT_CLR_ADPT_1 = 5'd22;
localparam STAT_CLR_ADPT_2 = 5'd23;
localparam WAIT_CNTR_1     = 5'd24;

// Commands
localparam ST_D  = 4'd0;  // Store data D to address/opreg
localparam CP_AR = 4'd1;  // Copy data from Address A to opreg A or opreg ALURES
localparam CP_RA = 4'd2;  // Copy data from opreg R0 or ALURES to Address A
localparam CP_OP = 4'd3;  // Copy data from opreg R1 (data/pointer) to opreg R2 (data/pointer)
localparam SHF   = 4'd4;  // Shift
localparam ADD   = 4'd5;  // Add
localparam STAT  = 4'd6;  // Check stats
localparam WAIT  = 4'd7;  // Wait
localparam JMPA  = 4'd8;  // Jump to address
localparam JMPP  = 4'd9;  // Jump to pointer
localparam IF_ZR = 4'd10; // If zero
localparam IF_OV = 4'd11; // If overflow

// command field definitions
localparam RR = 2'b00; // opreg to opreg
localparam RP = 2'b01; // opreg to ptr
localparam PR = 2'b10; // ptr to opreg
localparam PP = 2'b11; // ptr to ptr
localparam STAT_RBANK    = 3'b100;
localparam STATSRT_RNUM  = 5'd0;

`ifdef DWC_PMA_010D
localparam SMPLCNT_RNUM = 5'd8;
localparam STCNT_0_RNUM = 5'd10;
localparam STCNT_1_RNUM = 5'd11;
localparam STCNT_2_RNUM = 5'd12;
localparam STCNT_3_RNUM = 5'd13;
localparam STCNT_4_RNUM = 5'd14;
localparam STCNT_5_RNUM = 5'd15;
localparam STCNT_6_RNUM = 5'd16;
`else
localparam SMPLCNT_RNUM  = 5'd6;
localparam STCNT_0_RNUM  = 5'd7;
localparam STCNT_1_RNUM  = 5'd8;
localparam STCNT_2_RNUM  = 5'd9;
localparam STCNT_3_RNUM  = 5'd10;
localparam STCNT_4_RNUM  = 5'd11;
localparam STCNT_5_RNUM  = 5'd12;
localparam STCNT_6_RNUM  = 5'd13;
`endif

localparam STATSTOP_RNUM = 5'd20;
localparam ADPT_RBANK    = 3'b011;
localparam ADPTSRT_RNUM  = 5'd0;
localparam ADPTCFG3_RNUM = 5'd3;
localparam ADPTESL_RNUM  = 5'd27;
localparam ADPTRST_RNUM  = 5'd30;

// -----------------------------------------------------
// Detect a rising edge on stat/adapt status
// -----------------------------------------------------
dwc_e12mp_phy_x4_ns_gen_pcatch catch_stat_done_rising (
  .q               (stat_done_pulse),
  .rst             (fsm_rst),
  .clk             (cr_clk),
  .scan_mode_i     (scan_mode_i),
  .scan_set_rst_i  (scan_set_rst_i),
  .d               (rx_adapt_sts_i[0])
);
dwc_e12mp_phy_x4_ns_gen_pcatch catch_adapt_done_rising (
  .q               (adapt_done_pulse),
  .rst             (fsm_rst),
  .clk             (cr_clk),
  .scan_mode_i     (scan_mode_i),
  .scan_set_rst_i  (scan_set_rst_i),
  .d               (rx_adapt_sts_i[1])
);

// -----------------------------------------------------
// Instruction register bit mappings
// -----------------------------------------------------
// data fields
wire [3:0]  ireg_cmd          = ireg[15:12];
wire [3:0]  ireg_opreg2       = ireg[7:4];
wire [3:0]  ireg_opreg1       = ireg[3:0];
wire [1:0]  ireg_cp_type      = ireg[9:8];
wire [11:0] ireg_addr         = ireg[11:0];
wire        ireg_sgnd         = ireg[9];
wire        ireg_shiftr       = ireg[8];
wire [3:0]  ireg_shiftv       = ireg[7:4];
wire        ireg_alu_sub      = ireg[10];
wire [4:0]  ireg_alu_incdec   = ireg[8:4];
wire        ireg_thrsh_sgn    = ireg[4];
wire [3:0]  ireg_thrsh        = ireg[3:0];
wire [2:0]  ireg_stcnt_sel    = ireg[7:5];
// flag fields
wire        ireg_is_addr      = (ireg[11] == 1'b0);
wire        ireg_alures_sel   = (ireg[11] == 1'b1);
wire        ireg_ovflw_sel    = (ireg[11] == 1'b1);
wire        ireg_add_2_opregs = (ireg[11] == 1'b0);
wire        ireg_inc_inplace  = (ireg[9]  == 1'b0);
wire        ireg_stat_blk_sel = (ireg[11] == 1'b0);
wire        ireg_start_sel    = (ireg[10] == 1'b1);
wire        ireg_opr_en       = (ireg[9]  == 1'b1);
wire        ireg_esle_sel     = (ireg[8]  == 1'b0);
wire        wrmsk_disabled    = (wrmsk == 16'hFFFF); // disabled if all bits are selected for writing
wire        rdmsk_disabled    = (rdmsk == 16'hFFFF); // disabled if all bits are selected for reading
wire        alures_eq0        = (alures[16:0]==17'd0);
wire        wait_cnt_eq0      = (wait_cnt[26:0] == 27'd0);

// Mantis 7158 - Add a synchronizer to CR reg inputs to prevent
// CDC violations.  Note here that we are only concerned with
// removing metastability.  We are not concerned about
// convergence because the FW only polls single bit signals.
// Also, delay the ack by an additional cycle so the data
// value is sure to be settled due to the metastability
// modelling in the gen_sync module.

// For reads, delay the ACK by 5 cycles to match the synchronizer
// delay on the incoming read data.  For writes, just use the ACK
// signal as is.
assign cr_reg_rd_ack = cr_reg_ack & reg_rd_en;
assign cr_reg_wr_ack = cr_reg_ack & reg_wr_en;

always @(posedge cr_clk or posedge fsm_rst) begin
   if (fsm_rst) begin
      cr_reg_rd_data_d  <= 16'd0;
      cr_reg_rd_ack_d   <= 5'b00000;
   end else begin
      if (cr_reg_ack) begin
         cr_reg_rd_data_d <= cr_reg_rd_data;
      end
      cr_reg_rd_ack_d     <= {cr_reg_rd_ack_d[3:0], cr_reg_rd_ack};
   end
end

assign cr_reg_ack_sync = cr_reg_rd_ack_d[4] | cr_reg_wr_ack;

// Create a signal to gate the outgoing request once the ACK
// is received.  This allows the received data to be synchronized
wire req_dis = (|{cr_reg_rd_ack_d[3:0], cr_reg_rd_ack});

// Generate 16 synchronizers for each bit of the cr_mem_rd_data_d bus
generate for (i = 0; i<16; i = i+1) begin : sync_cr_bus_gen
   dwc_e12mp_phy_x4_ns_gen_sync sync_cr_bus (
     .q   (cr_reg_rd_data_sync[i]),
     .clk (cr_clk),
     .rst (fsm_rst),
     .d   (cr_reg_rd_data_d[i])
   );
end
endgenerate

// -----------------------------------------------------
// FSM for reading/executing sequences from the memory
// -----------------------------------------------------

// ---------------------------
// NEXT STATE LOGIC
// ---------------------------
always @* begin
  next_state     = IDLE;
  irq_msk_clr    = 1'b0;
  mem_req_nxt    = 1'b0;
  reg_req_nxt    = 1'b0;
  reg_wr_en_nxt  = 1'b0;
  reg_rd_en_nxt  = 1'b0;
  maddr_inc      = 1'b0;
  maddr_ld       = 1'b0;
  raddr_ld       = 1'b0;
  wr_data_ld     = 1'b0;
  wait_ld        = 1'b0;
  cmd_rdy        = 1'b0;
  opreg_en       = 16'd0;
  opreg_data_sel = 5'd0;
  sgnd           = 1'b0;
  shiftr         = 1'b0;
  shiftv         = 4'd0;
  alu_sub        = 1'b0;
  alu_ipa_sel    = 5'd0;
  alu_ipb_sel    = 5'd0;
  fsm_ld_data    = 16'd0;
  case(curr_state)
    IDLE: begin
      next_state = CMD_FETCH;
      mem_req_nxt = 1'b1;
      // load memory start address (start of main program)
      fsm_ld_data = {4'd0,MEM_START_ADDR};
      opreg_data_sel = SEL_FSM_DATA;
      maddr_ld = 1'b1;
    end

    CMD_FETCH: begin
      if (cr_mem_ack) begin
        next_state = CMD_DECODE;
        maddr_inc = 1'b1; // move address to next location in memory
      end else begin
        next_state = CMD_FETCH;
        mem_req_nxt = 1'b1;
      end
    end

    CMD_DECODE: begin
      if (fsm_ovrd_en_r & ~fsm_cmd_start_r) begin
        next_state = CMD_DECODE; // freeze FSM
        cmd_rdy = 1'b1;
      end
      else if (fsm_ovrd_en_r & fsm_jmp_en_r) begin
        next_state = CMD_FETCH;
        mem_req_nxt = 1'b1;
        fsm_ld_data = {4'd0,fsm_jmp_addr_r};
        opreg_data_sel = SEL_FSM_DATA;
        maddr_ld = 1'b1; // load new memory address to jump to
      end
      else if (irq) begin
        // clear interrupt mask
        irq_msk_clr = 1'b1;
        // go back to the start of memory
        next_state = IDLE;
        // reset read/write masks
        fsm_ld_data = 16'hFFFF; // restore read and write mask to all ones
        opreg_data_sel = SEL_FSM_DATA;
        opreg_en[SEL_WRMSK] = 1'b1; // restore write mask
        opreg_en[SEL_RDMSK] = 1'b1; // restore read mask
      end
      else begin
        case (ireg_cmd)
          ST_D: begin
            next_state = ST_D_1;
            // if field is an address, then store address
            if (ireg_is_addr) begin
              opreg_data_sel = SEL_IREG;
              raddr_ld = 1'b1;
            end
            // send memory request to get data
            mem_req_nxt = 1'b1;
          end

          CP_AR: begin
            next_state = WAIT_REG_ACK;
            // store read address
            opreg_data_sel = SEL_IREG;
            raddr_ld = 1'b1;
            // send read request
            reg_req_nxt = 1'b1;
            reg_rd_en_nxt = 1'b1;
          end
          
          CP_OP: begin
            // select source opreg
            opreg_data_sel = {1'b0,ireg_opreg2}; // select source opreg
            // check opreg copy type
            case(ireg_cp_type)
              RR: begin
                next_state = CMD_FETCH;
                // send read request to memory
                mem_req_nxt = 1'b1;
                opreg_en[ireg_opreg1] = 1'b1; // enable destination opreg
              end
              RP: begin
                next_state = CP_RP_1;
                // if write mask is disabled
                if (wrmsk_disabled)
                  wr_data_ld = 1'b1; // load opreg data into write register
                else
                  opreg_en[SEL_V0] = 1'b1; // store read data into VO
              end
              PR,PP: begin
                next_state = CP_PX_1;
                raddr_ld = 1'b1; // load opreg data into read address
                // send read request
                reg_req_nxt = 1'b1;
                reg_rd_en_nxt = 1'b1;
              end
            endcase
          end
          
          CP_RA: begin
            next_state = CP_RA_1;
            opreg_data_sel = ireg_alures_sel ? SEL_ALURES : SEL_R0; // select source opreg
            // if write mask is disabled
            if (wrmsk_disabled)
              wr_data_ld = 1'b1; // load opreg data into write register
            else
              opreg_en[SEL_V0] = 1'b1; // store read data into VO
          end

          SHF: begin
            next_state = CMD_FETCH;
            mem_req_nxt = 1'b1;
            sgnd   = ireg_sgnd; // check if signed shift
            shiftr = ireg_shiftr; // shift right select
            shiftv = ireg_shiftv; // shift value
            // in place shift of opreg
            opreg_data_sel = {1'b0,ireg_opreg1};
            opreg_en[ireg_opreg1] = 1'b1;
          end

          ADD: begin
            // if adding 2 opregs
            if (ireg_add_2_opregs) begin
              next_state = CMD_FETCH;
              mem_req_nxt = 1'b1;
              alu_sub = ireg_alu_sub;
              alu_ipa_sel = {1'b0,ireg_opreg1};
              alu_ipb_sel = {1'b0,ireg_opreg2};
              opreg_data_sel = SEL_ALURES_NXT;
              opreg_en[SEL_ALURES] = 1'b1;
            end
            // else if inc/dec an opreg in-place (i.e. not a pointer)
            else if (ireg_inc_inplace) begin
              next_state = CMD_FETCH;
              mem_req_nxt = 1'b1;
              alu_sub = ireg_alu_sub;
              alu_ipa_sel = {1'b0,ireg_opreg1};
              alu_ipb_sel = SEL_FSM_DATA;
              fsm_ld_data = {11'd0,ireg_alu_incdec}; // load inc/dec value
              opreg_data_sel = SEL_ALURES_NXT;
              opreg_en[ireg_opreg1] = 1'b1; // in-place inc/dec
              opreg_en[SEL_ALURES] = 1'b1; // update alu result
            end
            // else doing an inc/dec via an opreg pointer
            else begin
              next_state = ADD_1;
              // store read address
              opreg_data_sel = {1'b0,ireg_opreg1};
              raddr_ld = 1'b1;
              // send read request
              reg_req_nxt = 1'b1;
              reg_rd_en_nxt = 1'b1;
            end
          end

          STAT: begin
            // If writing "start"
            if (ireg_start_sel) begin
              next_state = STAT_START_1;
              // load address (start bit address)
              fsm_ld_data = ireg_stat_blk_sel ? {5'd0,`DWC_E12MP_X4NS_CR_TYPE_LANE,STAT_RBANK,STATSRT_RNUM}
                                              : {5'd0,`DWC_E12MP_X4NS_CR_TYPE_LANE,ADPT_RBANK,ADPTSRT_RNUM};
              opreg_data_sel = SEL_FSM_DATA;
              raddr_ld = 1'b1;
              // read register that has start bit
              reg_req_nxt = 1'b1;
              reg_rd_en_nxt = 1'b1;
            end
            // else check if we are just performing the required operation (read and/or comparison)
            else if (ireg_opr_en) begin
              next_state = STAT_OPR_1;
              fsm_ld_data = ireg_stat_blk_sel ? 16'h7FFF : // smpl_cnt1, stcnt_X
                            ireg_esle_sel     ? 16'hFF00   // even slicer
                                              : 16'h00FF;  // odd slicer
              opreg_data_sel = SEL_FSM_DATA;
              opreg_en[SEL_RDMSK] = 1'b1; // store read mask
            end
            // else, nothing to do, go to next command
            else begin
              next_state = CMD_FETCH;
              mem_req_nxt = 1'b1;
            end
          end

          WAIT: begin
            next_state = WAIT_CNTR_1;
            wait_ld = 1'b1;
          end

          JMPA: begin
            next_state = CMD_FETCH;
            mem_req_nxt = 1'b1;
            // select between address and pointer
            opreg_data_sel = SEL_IREG;
            maddr_ld = 1'b1; // load new memory address to jump to
          end

          JMPP: begin
            next_state = CMD_FETCH;
            mem_req_nxt = 1'b1;
            // Load pointer
            opreg_data_sel = {1'b0,ireg_opreg1};
            maddr_ld = 1'b1; // load new memory address to jump to
          end

          IF_ZR: begin
            next_state = CMD_FETCH;
            mem_req_nxt = 1'b1;
            // IF_ZW instruction will proceed if alures=0, otherwise go to false_addr
            //
            // check if need to load "false_addr" otherwise keep current
            // address (already pointing to next location)
            if (~alures_eq0) begin
              fsm_ld_data = {4'd0,ireg_addr};
              opreg_data_sel = SEL_FSM_DATA;
              maddr_ld = 1'b1; // load new memory address to jump to
            end
          end
          
          IF_OV: begin
            next_state = CMD_FETCH;
            mem_req_nxt = 1'b1;
            // IF_OV instruction will proceed if overflow, otherwise go to false_addr
            //
            // check if need to load "false_addr" otherwise keep current
            // address (already pointing to next location)
            if (~alures[16]) begin
              fsm_ld_data = {4'd0,ireg_addr};
              opreg_data_sel = SEL_FSM_DATA;
              maddr_ld = 1'b1; // load new memory address to jump to
            end
          end
          
          default: begin
            next_state = CMD_FETCH;
            mem_req_nxt = 1'b1;
          end
        endcase
      end
    end

    // WAIT_REG_ACK: wait for register read/write ack
    WAIT_REG_ACK: begin
      if (cr_reg_ack_sync) begin
        next_state = CMD_FETCH;
        mem_req_nxt = 1'b1;
        // if we're doing a read, then store the extracted data into REGA or
        // ALURES, based on ireg_alures_sel
        if (reg_rd_en) begin
          opreg_data_sel = SEL_REG_RDATA_XTRCT;
          opreg_en[SEL_REGA]   = ~ireg_alures_sel;
          opreg_en[SEL_ALURES] = ireg_alures_sel;
        end
      end else begin
        next_state = WAIT_REG_ACK;
        reg_req_nxt = 1'b1;
        // preserve the requested operation (either read or write)
        reg_wr_en_nxt = reg_wr_en;
        reg_rd_en_nxt = reg_rd_en;
      end
    end

    // ST_D_1: get store data
    ST_D_1: begin
      if (cr_mem_ack) begin
        maddr_inc = 1'b1; // move address to next location in memory
        opreg_data_sel = SEL_MEM_RDATA;

        // if storing to an address
        if (ireg_is_addr) begin
          // if write mask is disabled
          if (wrmsk_disabled) begin
            next_state = WAIT_REG_ACK;
            wr_data_ld = 1'b1; // capture cr_mem_rd_data (i.e. store wr data)
            reg_req_nxt = 1'b1;
            reg_wr_en_nxt = 1'b1;
          end
          // else the write mask is not all ones (i.e. not all bits are selected for write), then
          // we need to read the destination register first, apply the write mask, then write the new data
          else begin
            next_state = WRMSK_1;
            // store read data into VO
            opreg_en[SEL_V0] = 1'b1;
            // then read register value of destination (address is already loaded)
            // send read request
            reg_req_nxt = 1'b1;
            reg_rd_en_nxt = 1'b1;
          end
        end
        // else we are storing to an opreg
        else begin
          next_state = CMD_FETCH;
          mem_req_nxt = 1'b1;
          opreg_en[ireg_opreg1] = 1'b1; // get destination opreg from ireg_opreg1
        end
      end else begin
        next_state = ST_D_1;
        mem_req_nxt = 1'b1;
      end
    end

    // WRMSK_1: read destination register and use for write mask
    WRMSK_1: begin
      if (cr_reg_ack_sync) begin
        next_state = WAIT_REG_ACK;
        // load stored write data from V0, the write mask will be applied in the process
        opreg_data_sel = SEL_V0;
        wr_data_ld = 1'b1; // capture mask(V0,cr_reg_rd_data_sync)
        reg_req_nxt = 1'b1;
        reg_wr_en_nxt = 1'b1;
      end else begin
        next_state = WRMSK_1;
        reg_req_nxt = 1'b1;
        reg_rd_en_nxt = 1'b1;
      end
    end

    // CP_RA_1: get destination address
    CP_RA_1: begin
      opreg_data_sel = SEL_IREG;
      raddr_ld = 1'b1; // store destination address
      // if write mask is disabled
      if (wrmsk_disabled) begin
        next_state = WAIT_REG_ACK;
        // send write request
        reg_req_nxt = 1'b1;
        reg_wr_en_nxt = 1'b1;
      end
      else begin
        next_state = WRMSK_1;
        // then read register value of destination
        // send read request
        reg_req_nxt = 1'b1;
        reg_rd_en_nxt = 1'b1;
      end
    end

    // CP_RP_1: load destination address from pointer
    CP_RP_1: begin
      opreg_data_sel = {1'b0,ireg_opreg1}; // select pointer opreg
      raddr_ld = 1'b1; // load address from pointer
      // if write mask is disabled
      if (wrmsk_disabled) begin
        next_state = WAIT_REG_ACK;
        // send write request
        reg_req_nxt = 1'b1;
        reg_wr_en_nxt = 1'b1;
      end
      else begin
        next_state = WRMSK_1;
        // then read register value of destination
        // send read request
        reg_req_nxt = 1'b1;
        reg_rd_en_nxt = 1'b1;
      end
    end

    // CP_PX_1: get source data from pointer and write to destination X (i.e. opreg or ptr)
    CP_PX_1: begin
      if (cr_reg_ack_sync) begin
        // use read mask
        opreg_data_sel = SEL_REG_RDATA_XTRCT;
        // if storing to opreg
        if (ireg_cp_type == PR) begin
          next_state = CMD_FETCH;
          opreg_en[ireg_opreg1] = 1'b1; // get destination opreg from ireg_opreg1
        end
        // else we are storing to pointer
        else begin
          next_state = CP_RP_1;
          // if write mask is disabled
          if (wrmsk_disabled)
            wr_data_ld = 1'b1; // load opreg data into write register
          else
            opreg_en[SEL_V0] = 1'b1; // store read data into VO
        end
      end else begin
        next_state = CP_PX_1;
        reg_req_nxt = 1'b1;
        reg_rd_en_nxt = 1'b1;
      end
    end

    // ADD_1: read value from pointer
    ADD_1: begin
      if (cr_reg_ack_sync) begin
        next_state = ADD_2;
        opreg_data_sel = SEL_REG_RDATA_XTRCT;
        opreg_en[SEL_REGA] = 1'b1;
      end else begin
        next_state = ADD_1;
        reg_req_nxt = 1'b1;
        reg_rd_en_nxt = 1'b1;
      end
    end

    // ADD_2: increment/decrement value
    ADD_2: begin
      next_state = WAIT_REG_ACK;
      alu_sub = ireg_alu_sub;
      alu_ipa_sel = SEL_REGA;
      alu_ipb_sel = SEL_FSM_DATA;
      fsm_ld_data = {11'd0,ireg_alu_incdec}; // load inc/dec value
      opreg_data_sel = SEL_ALURES_NXT;
      opreg_en[SEL_ALURES] = 1'b1; // update alu result
      wr_data_ld = 1'b1; // capture result (i.e. write data)
      // send write request
      reg_req_nxt = 1'b1;
      reg_wr_en_nxt = 1'b1;
    end

    // STAT_START_1: assert start bit
    STAT_START_1: begin
      // if received ack, i.e. read start register, then write back 1'b1 to start bit
      if (cr_reg_ack_sync) begin
        next_state = STAT_START_2;
        // load write data (start bit = 1),
        // the write mask will move it to the correct bit location
        fsm_ld_data = 16'd1;
        opreg_data_sel = SEL_FSM_DATA;
        wr_data_ld = 1'b1;
        // send write request
        reg_req_nxt = 1'b1;
        reg_wr_en_nxt = 1'b1;
      end else begin
        next_state = STAT_START_1;
        reg_req_nxt = 1'b1;
        reg_rd_en_nxt = 1'b1;
        // NOTE: we can load the write mask here because we know that the ack
        // for Read will never assert in the same cycle as the request, so we
        // will definitely hit this part of the code at least once.
        //
        // load write mask (start bit = 1)
        fsm_ld_data = ireg_stat_blk_sel ? 16'h8000 : 16'h4000;
        opreg_data_sel = SEL_FSM_DATA;
        opreg_en[SEL_WRMSK] = 1'b1; // store write mask
      end
    end

    // STAT_START_2: wait for write ack
    STAT_START_2: begin
      // if received ack, then deassert request and load read mask
      if (cr_reg_ack_sync) begin
        next_state = STAT_WAIT_DN;
        // load read mask
        fsm_ld_data = ireg_stat_blk_sel ? 16'h7FFF : // smpl_cnt1, stcnt_X
                      ireg_esle_sel     ? 16'hFF00   // even slicer
                                        : 16'h00FF;  // odd slicer
        opreg_data_sel = SEL_FSM_DATA;
        opreg_en[SEL_RDMSK] = 1'b1; // store read mask
      end else begin
        next_state = STAT_START_2;
        reg_req_nxt = 1'b1;
        reg_wr_en_nxt = 1'b1;
      end
    end

    // STAT_WAIT_DN: wait for done
    STAT_WAIT_DN: begin
      // Mantis 6705: check if there is an interrupt 
      if (irq) begin
        // Mantis 6758 - Set appropriate RESET registers within
        // ADAPT or STATS block in PMA when an interrupt occurs
        // If waiting for ADAPT to complete, write the ADPT_RESET register
        if (~ireg_stat_blk_sel) begin
          // load write address for ADPT_RESET
          fsm_ld_data = {5'd0,`DWC_E12MP_X4NS_CR_TYPE_LANE,ADPT_RBANK,ADPTRST_RNUM};  // ADPT_RESET
        end
        // else if waiting for ADAPT to complete, write the ADPT_RESET register
        else begin
          // load write address for STAT_STOP
          fsm_ld_data = {5'd0,`DWC_E12MP_X4NS_CR_TYPE_LANE,STAT_RBANK,STATSTOP_RNUM};  // STAT_STOP
        end
        opreg_data_sel = SEL_FSM_DATA;
        raddr_ld = 1'b1;
        next_state = STAT_CLR_ADPT_1;
      end
      // check if stat/adapt done is asserted
      else if (ireg_stat_blk_sel ? stat_done_pulse : adapt_done_pulse) begin
        // if opr_en bit is asserted then perform it, otherwise exit stat
        // command cleanly (i.e. read/write masks)
        next_state = ireg_opr_en ? STAT_OPR_1 : STAT_RST_MSK;
      end else begin
        next_state = STAT_WAIT_DN;
      end
    end

    // STAT_OPR_1: begin operation
    STAT_OPR_1: begin
      next_state = ireg_stat_blk_sel ? STAT_CORR_1 : STAT_ESL_RD;
      // load read address
      fsm_ld_data = ireg_stat_blk_sel ? {5'd0,`DWC_E12MP_X4NS_CR_TYPE_LANE,STAT_RBANK,SMPLCNT_RNUM}  // smpl_cnt1
                                      : {5'd0,`DWC_E12MP_X4NS_CR_TYPE_LANE,ADPT_RBANK,ADPTESL_RNUM}; // even/odd slicer
      opreg_data_sel = SEL_FSM_DATA;
      raddr_ld = 1'b1;
      // send read request
      reg_req_nxt = 1'b1;
      reg_rd_en_nxt = 1'b1;
    end

    // STAT_CORR_1: store smpl_cnt1>>2
    STAT_CORR_1: begin
      // if received ack (i.e. smpl_cnt1 read was completed), then read stcnt_X
      if (cr_reg_ack_sync) begin
        next_state = STAT_CORR_2;
        // select read data
        opreg_data_sel = SEL_REG_RDATA_XTRCT; // using read mask to remove done bit
        // divide smpl_cnt1 by 2
        sgnd   = 1'b0; // smpl_cnt1 value is unsigned
        shiftr = 1'b1; // shift right select
        shiftv = 4'd1; // shift value
        // store to opreg V0
        opreg_en[SEL_V0] = 1'b1;
      end else begin
        next_state = STAT_CORR_1;
        reg_req_nxt = 1'b1;
        reg_rd_en_nxt = 1'b1;
      end
    end

    // STAT_CORR_2: perform (smpl_cnt1>>2) +/- (2^thrsh-1)
    STAT_CORR_2: begin
      next_state = STAT_CORR_3;
      alu_sub = ireg_thrsh_sgn;
      alu_ipa_sel = SEL_V0; // smpl_cnt1>>2
      alu_ipb_sel = SEL_FSM_DATA; // threshold value
      fsm_ld_data = (16'd1<<ireg_thrsh) - 16'd1;
      opreg_data_sel = SEL_ALURES_NXT;
      opreg_en[SEL_ALURES] = 1'b1; // update alu result
      opreg_en[SEL_V1] = 1'b1; // store result to opreg V1
    end

    // STAT_CORR_3: read stcnt_X
    STAT_CORR_3: begin
      next_state = STAT_CORR_4;
      // load read address of stcnt_X
      fsm_ld_data[15:5] = {5'd0,`DWC_E12MP_X4NS_CR_TYPE_LANE,STAT_RBANK};
      opreg_data_sel = SEL_FSM_DATA;
      raddr_ld = 1'b1;
      case (ireg_stcnt_sel) // check stcnt number, and load corresponding register number
        3'd0:    fsm_ld_data[4:0] = STCNT_0_RNUM;
        3'd1:    fsm_ld_data[4:0] = STCNT_1_RNUM;
        3'd2:    fsm_ld_data[4:0] = STCNT_2_RNUM;
        3'd3:    fsm_ld_data[4:0] = STCNT_3_RNUM;
        3'd4:    fsm_ld_data[4:0] = STCNT_4_RNUM;
        3'd5:    fsm_ld_data[4:0] = STCNT_5_RNUM;
        3'd6:    fsm_ld_data[4:0] = STCNT_6_RNUM;
        default: fsm_ld_data[4:0] = STCNT_3_RNUM;
      endcase                    
      // send read request
      reg_req_nxt = 1'b1;
      reg_rd_en_nxt = 1'b1;
    end

    // STAT_CORR_4: read stcnt_X
    STAT_CORR_4: begin
      // if received ack (i.e. stcnt_X read was completed), then perform comparison
      if (cr_reg_ack_sync) begin
        next_state = STAT_CORR_5;
        // select read data
        opreg_data_sel = SEL_REG_RDATA_XTRCT; // using read mask to remove done bit
        opreg_en[SEL_V2] = 1'b1; // store to opreg V2
      end else begin
        next_state = STAT_CORR_4;
        reg_req_nxt = 1'b1;
        reg_rd_en_nxt = 1'b1;
      end
    end

    // STAT_CORR_5: perform stcnt_X - ((smpl_cnt1>>2) +/- (2^thrsh-1))
    STAT_CORR_5: begin
      next_state = STAT_RST_MSK;
      alu_sub = 1'b1;
      alu_ipa_sel = SEL_V2; // stcnt_X
      alu_ipb_sel = SEL_V1; // (smpl_cnt1>>2) +/- (2^thrsh-1)
      opreg_data_sel = SEL_ALURES_NXT;
      opreg_en[SEL_ALURES] = 1'b1; // update alu result
    end

    // STAT_ESL_RD: read error slicer value
    STAT_ESL_RD: begin
      if (cr_reg_ack_sync) begin
        next_state = STAT_RST_MSK;
        opreg_data_sel = SEL_REG_RDATA_XTRCT;
        opreg_en[SEL_REGA] = 1'b1;
      end else begin
        next_state = STAT_ESL_RD;
        reg_req_nxt = 1'b1;
        reg_rd_en_nxt = 1'b1;
      end
    end

    // STAT_RST_MSK: reset read and write masks
    STAT_RST_MSK: begin
      fsm_ld_data = 16'hFFFF; // restore read and write mask to all ones
      opreg_data_sel = SEL_FSM_DATA;
      opreg_en[SEL_WRMSK] = 1'b1; // restore write mask
      opreg_en[SEL_RDMSK] = 1'b1; // restore read mask
      // fetch new command
      next_state = CMD_FETCH;
      mem_req_nxt = 1'b1;
    end

    // STAT_CLR_ADPT_1: clear adaptation enables (reset masks)
    // This intermeidate state is required to reset the masks
    // so that registers can be written in the next state.
    STAT_CLR_ADPT_1: begin
      fsm_ld_data = 16'hFFFF; // restore read and write mask to all ones
      opreg_data_sel = SEL_FSM_DATA;
      opreg_en[SEL_WRMSK] = 1'b1; // restore write mask
      opreg_en[SEL_RDMSK] = 1'b1; // restore read mask
      // Move to STAT_CLR_ADPT_2
      next_state = STAT_CLR_ADPT_2;
    end

    // STAT_CLR_ADPT_2: clear adaptation enables (perform register writes)
    STAT_CLR_ADPT_2: begin
      if (cr_reg_ack_sync) begin
        // reset read/write masks
        fsm_ld_data = 16'hFFFF; // restore read and write mask to all ones
        opreg_data_sel = SEL_FSM_DATA;
        opreg_en[SEL_WRMSK] = 1'b1; // restore write mask
        opreg_en[SEL_RDMSK] = 1'b1; // restore read mask
        // clear interrupt mask
        irq_msk_clr = 1'b1;
        // go back to the start of memory
        next_state = IDLE;
      end
      else begin
        next_state = STAT_CLR_ADPT_2;
        // Mantis 6758 - Load write data to 1'b1 to assert
        // reset/stop signals. These bits are self clearing
        fsm_ld_data = 16'd1;
        opreg_data_sel = SEL_FSM_DATA;
        wr_data_ld = 1'b1;
        // send write request
        reg_req_nxt = 1'b1;
        reg_wr_en_nxt = 1'b1;
      end
    end

    // WAIT_CNTR_1: remain in this state until wait counter hits zero
    WAIT_CNTR_1: begin
      // Mantis 6705: check if there is an interrupt 
      if (irq) begin
        // reset read/write masks
        fsm_ld_data = 16'hFFFF; // restore read and write mask to all ones
        opreg_data_sel = SEL_FSM_DATA;
        opreg_en[SEL_WRMSK] = 1'b1; // restore write mask
        opreg_en[SEL_RDMSK] = 1'b1; // restore read mask
        // clear interrupt mask
        irq_msk_clr = 1'b1;
        // go back to the start of memory
        next_state = IDLE;
      end else if (wait_cnt_eq0) begin
        next_state = CMD_FETCH;
        mem_req_nxt = 1'b1;
      end else begin
        next_state = WAIT_CNTR_1;
      end
    end

    default: begin
      next_state = IDLE;
    end
  endcase
end

// ---------------------------
// FSM STATE LOGIC
// ---------------------------
always @(posedge cr_clk or posedge fsm_rst) begin
 if (fsm_rst)
   curr_state <= IDLE;
 else
   curr_state <= next_state;
end

// ---------------------------
// FSM VARIABLE LOGIC
// ---------------------------
always @(posedge cr_clk or posedge fsm_rst) begin
  if (fsm_rst) begin
    // request signals
    mem_req   <= 1'b0;
    reg_req   <= 1'b0;
    reg_wr_en <= 1'b0;
    reg_rd_en <= 1'b0;
    // internal instruction registers
    ireg         <= 16'd0;
    // registers for output
    maddr        <= 12'd0;
    raddr        <= 11'd0;
    wr_data      <= 16'd0;
    // wait counter
    wait_cnt     <= 27'd0;
    // opregs
    r0           <= 16'd0;
    r1           <= 16'd0;
    r2           <= 16'd0;
    r3           <= 16'd0;
    r4           <= 16'd0;
    r5           <= 16'd0;
    r6           <= 16'd0;
    r7           <= 16'd0;
    v0           <= 16'd0;
    v1           <= 16'd0;
    v2           <= 16'd0;
    v3           <= 16'd0;
    rega         <= 16'd0;
    alures       <= 17'd0;// 17bits
    rdmsk        <= 16'hFFFF;
    wrmsk        <= 16'hFFFF;
  end
  else begin
    // ----------------------------------------------
    // request signals
    // ----------------------------------------------
    mem_req   <= mem_req_nxt;
    reg_req   <= reg_req_nxt & ~req_dis;
    reg_wr_en <= reg_wr_en_nxt;
    reg_rd_en <= reg_rd_en_nxt;
    
    // ----------------------------------------------
    // internal instruction register
    // ----------------------------------------------
    ireg <= maddr_inc ? cr_mem_rd_data : ireg;
    
    // ----------------------------------------------
    // registers for output
    // ----------------------------------------------
    maddr   <= maddr_ld   ? opreg_data[11:0] : (maddr_inc ? (maddr+12'd1) : maddr);
    raddr   <= raddr_ld   ? opreg_data[10:0] : raddr;
    wr_data <= wr_data_ld ? opreg_data_wrmsk : wr_data;

    // ----------------------------------------------
    // wait counter
    // ----------------------------------------------
    if (wait_ld)
      wait_cnt <= {15'd0,ireg[7:0],4'd0} << ireg[11:8];
    else if (~wait_cnt_eq0)
      wait_cnt <= wait_cnt - 27'd1;

    // ----------------------------------------------
    // opregs
    // ----------------------------------------------
    if (opreg_en[SEL_R0    ]) r0     <= opreg_data;
    if (opreg_en[SEL_R1    ]) r1     <= opreg_data;
    if (opreg_en[SEL_R2    ]) r2     <= opreg_data;
    if (opreg_en[SEL_R3    ]) r3     <= opreg_data;
    if (opreg_en[SEL_R4    ]) r4     <= opreg_data;
    if (opreg_en[SEL_R5    ]) r5     <= opreg_data;
    if (opreg_en[SEL_R6    ]) r6     <= opreg_data;
    if (opreg_en[SEL_R7    ]) r7     <= opreg_data;
    if (opreg_en[SEL_V0    ]) v0     <= opreg_data;
    if (opreg_en[SEL_V1    ]) v1     <= opreg_data;
    if (opreg_en[SEL_V2    ]) v2     <= opreg_data;
    if (opreg_en[SEL_V3    ]) v3     <= opreg_data;
    if (opreg_en[SEL_REGA  ]) rega   <= opreg_data;
    if (opreg_en[SEL_RDMSK ]) rdmsk  <= opreg_data;
    if (opreg_en[SEL_WRMSK ]) wrmsk  <= opreg_data;
    
    // ALU Result is a special case, need to store overflow bit
    if (opreg_en[SEL_ALURES]) alures <= {alu_ovflw,opreg_data};
  end
end
    
// ----------------------------------------------
// ALU inputs (A,B) and result
// ----------------------------------------------

// Select ALU A input
always @* begin
  case(alu_ipa_sel)
    SEL_R0       : alu_ipa = r0;
    SEL_R1       : alu_ipa = r1;
    SEL_R2       : alu_ipa = r2;
    SEL_R3       : alu_ipa = r3;
    SEL_R4       : alu_ipa = r4;
    SEL_R5       : alu_ipa = r5;
    SEL_R6       : alu_ipa = r6;
    SEL_R7       : alu_ipa = r7;
    SEL_V0       : alu_ipa = v0;
    SEL_V1       : alu_ipa = v1;
    SEL_V2       : alu_ipa = v2;
    SEL_V3       : alu_ipa = v3;
    SEL_REGA     : alu_ipa = rega;
    SEL_ALURES   : alu_ipa = alures[15:0];
    SEL_RDMSK    : alu_ipa = rdmsk;
    SEL_WRMSK    : alu_ipa = wrmsk;
    SEL_FSM_DATA : alu_ipa = fsm_ld_data; 
    default: alu_ipa = 16'd0;
  endcase
end

// Select ALU B input
always @* begin
  case(alu_ipb_sel)
    SEL_R0       : alu_ipb = r0;
    SEL_R1       : alu_ipb = r1;
    SEL_R2       : alu_ipb = r2;
    SEL_R3       : alu_ipb = r3;
    SEL_R4       : alu_ipb = r4;
    SEL_R5       : alu_ipb = r5;
    SEL_R6       : alu_ipb = r6;
    SEL_R7       : alu_ipb = r7;
    SEL_V0       : alu_ipb = v0;
    SEL_V1       : alu_ipb = v1;
    SEL_V2       : alu_ipb = v2;
    SEL_V3       : alu_ipb = v3;
    SEL_REGA     : alu_ipb = rega;
    SEL_ALURES   : alu_ipb = alures[15:0];
    SEL_RDMSK    : alu_ipb = rdmsk;
    SEL_WRMSK    : alu_ipb = wrmsk;
    SEL_FSM_DATA : alu_ipb = fsm_ld_data; 
    default: alu_ipb = 16'd0;
  endcase
end

// ALU result
assign alures_nxt[16:0] = alu_sub ? ({1'b0,alu_ipa} - {1'b0,alu_ipb}) : ({1'b0,alu_ipa} + {1'b0,alu_ipb});
    
// ----------------------------------------------
// Select opreg data and apply shift
// ----------------------------------------------

// Select opreg data
always @* begin
  case(opreg_data_sel)
    SEL_R0              : opreg_data_preshf = r0;
    SEL_R1              : opreg_data_preshf = r1;
    SEL_R2              : opreg_data_preshf = r2;
    SEL_R3              : opreg_data_preshf = r3;
    SEL_R4              : opreg_data_preshf = r4;
    SEL_R5              : opreg_data_preshf = r5;
    SEL_R6              : opreg_data_preshf = r6;
    SEL_R7              : opreg_data_preshf = r7;
    SEL_V0              : opreg_data_preshf = v0;
    SEL_V1              : opreg_data_preshf = v1;
    SEL_V2              : opreg_data_preshf = v2;
    SEL_V3              : opreg_data_preshf = v3;
    SEL_REGA            : opreg_data_preshf = rega;
    SEL_ALURES          : opreg_data_preshf = alures[15:0];
    SEL_RDMSK           : opreg_data_preshf = rdmsk;
    SEL_WRMSK           : opreg_data_preshf = wrmsk;
    SEL_FSM_DATA        : opreg_data_preshf = fsm_ld_data;
    SEL_IREG            : opreg_data_preshf = ireg;
    SEL_ALURES_NXT      : opreg_data_preshf = alures_nxt[15:0]; 
    SEL_MEM_RDATA       : opreg_data_preshf = cr_mem_rd_data; 
    SEL_REG_RDATA       : opreg_data_preshf = cr_reg_rd_data_sync;
    SEL_REG_RDATA_XTRCT : opreg_data_preshf = reg_rd_data_xtrct;
    default: opreg_data_preshf = 16'd0;
  endcase
end

// Apply shift
assign opreg_data_32b = shiftr ? ({{16{sgnd&opreg_data_preshf[15]}},opreg_data_preshf[15:0]} >> shiftv)
                               : (opreg_data_preshf << shiftv);
assign opreg_data = opreg_data_32b[15:0];

// Set overflow bit
assign alu_ovflw = (opreg_data_sel==SEL_ALURES)     ? alures[16] :
                   (opreg_data_sel==SEL_ALURES_NXT) ? alures_nxt[16]
                                                    : 1'b0;
    
// ----------------------------------------------
// Apply read and write masks
// ----------------------------------------------

// Apply read mask
assign reg_rd_data_xtrct_and = rdmsk & cr_reg_rd_data_sync;
always @* begin
  casez(rdmsk)
    16'b????_????_????_???1 : reg_rd_data_xtrct =  reg_rd_data_xtrct_and;
    16'b????_????_????_??10 : reg_rd_data_xtrct = { 1'd0, reg_rd_data_xtrct_and[15:1]};
    16'b????_????_????_?100 : reg_rd_data_xtrct = { 2'd0, reg_rd_data_xtrct_and[15:2]};
    16'b????_????_????_1000 : reg_rd_data_xtrct = { 3'd0, reg_rd_data_xtrct_and[15:3]};
    16'b????_????_???1_0000 : reg_rd_data_xtrct = { 4'd0, reg_rd_data_xtrct_and[15:4]};
    16'b????_????_??10_0000 : reg_rd_data_xtrct = { 5'd0, reg_rd_data_xtrct_and[15:5]};
    16'b????_????_?100_0000 : reg_rd_data_xtrct = { 6'd0, reg_rd_data_xtrct_and[15:6]};
    16'b????_????_1000_0000 : reg_rd_data_xtrct = { 7'd0, reg_rd_data_xtrct_and[15:7]};
    16'b????_???1_0000_0000 : reg_rd_data_xtrct = { 8'd0, reg_rd_data_xtrct_and[15:8]};
    16'b????_??10_0000_0000 : reg_rd_data_xtrct = { 9'd0, reg_rd_data_xtrct_and[15:9]};
    16'b????_?100_0000_0000 : reg_rd_data_xtrct = {10'd0, reg_rd_data_xtrct_and[15:10]};
    16'b????_1000_0000_0000 : reg_rd_data_xtrct = {11'd0, reg_rd_data_xtrct_and[15:11]};
    16'b???1_0000_0000_0000 : reg_rd_data_xtrct = {12'd0, reg_rd_data_xtrct_and[15:12]};
    16'b??10_0000_0000_0000 : reg_rd_data_xtrct = {13'd0, reg_rd_data_xtrct_and[15:13]};
    16'b?100_0000_0000_0000 : reg_rd_data_xtrct = {14'd0, reg_rd_data_xtrct_and[15:14]};
    16'b1000_0000_0000_0000 : reg_rd_data_xtrct = {15'd0, reg_rd_data_xtrct_and[15]};
    default: reg_rd_data_xtrct = 16'd0;
  endcase
end

// Apply write mask
always @* begin
  casez(wrmsk)
    16'b????_????_????_???1 : opreg_data_wrmsk_shft = opreg_data;
    16'b????_????_????_??10 : opreg_data_wrmsk_shft = {opreg_data[14:0], 1'd0};
    16'b????_????_????_?100 : opreg_data_wrmsk_shft = {opreg_data[13:0], 2'd0};
    16'b????_????_????_1000 : opreg_data_wrmsk_shft = {opreg_data[12:0], 3'd0};
    16'b????_????_???1_0000 : opreg_data_wrmsk_shft = {opreg_data[11:0], 4'd0};
    16'b????_????_??10_0000 : opreg_data_wrmsk_shft = {opreg_data[10:0], 5'd0};
    16'b????_????_?100_0000 : opreg_data_wrmsk_shft = {opreg_data[9:0] , 6'd0};
    16'b????_????_1000_0000 : opreg_data_wrmsk_shft = {opreg_data[8:0] , 7'd0};
    16'b????_???1_0000_0000 : opreg_data_wrmsk_shft = {opreg_data[7:0] , 8'd0};
    16'b????_??10_0000_0000 : opreg_data_wrmsk_shft = {opreg_data[6:0] , 9'd0};
    16'b????_?100_0000_0000 : opreg_data_wrmsk_shft = {opreg_data[5:0] ,10'd0};
    16'b????_1000_0000_0000 : opreg_data_wrmsk_shft = {opreg_data[4:0] ,11'd0};
    16'b???1_0000_0000_0000 : opreg_data_wrmsk_shft = {opreg_data[3:0] ,12'd0};
    16'b??10_0000_0000_0000 : opreg_data_wrmsk_shft = {opreg_data[2:0] ,13'd0};
    16'b?100_0000_0000_0000 : opreg_data_wrmsk_shft = {opreg_data[1:0] ,14'd0};
    16'b1000_0000_0000_0000 : opreg_data_wrmsk_shft = {opreg_data[0]   ,15'd0};
    default: opreg_data_wrmsk_shft = 16'd0;
  endcase
end
generate for (i = 0; i<16; i = i+1) begin:write_mask
  assign opreg_data_wrmsk[i] = wrmsk[i] ? opreg_data_wrmsk_shft[i] : cr_reg_rd_data_sync[i];
end
endgenerate

    
// ----------------------------------------------
// Set outputs to Memory arbiter
// ----------------------------------------------
assign cr_mem_req     = mem_req;
assign cr_mem_rd_en   = mem_req; // All ROM requests are read
assign cr_mem_wr_en   = 1'b0;   // Memory is a ROM
assign cr_mem_wr_data = 16'd0;// Memory is a ROM
`ifdef DWC_E12MP_X4NS_SRAM_SUPPORT
// By default, use RAM0 if sram is not bypassed
assign cr_mem_addr    = sram_bypass ? {`DWC_E12MP_X4NS_CR_TYPE_RAW_PCS_ROM0,maddr[11:0]} :
                                      {`DWC_E12MP_X4NS_CR_TYPE_RAW_PCS_RAM0,maddr[11:0]};
`else
// By default, use ROM0
assign cr_mem_addr    = {`DWC_E12MP_X4NS_CR_TYPE_RAW_PCS_ROM0,maddr[11:0]};
`endif

// ----------------------------------------------
// Set outputs to Register arbiter
// ----------------------------------------------

// The channel field must be set to zero for common registers,
// so only use the "cr_chan_addr" input if addressing a lane register.
assign chan_field  = (raddr[10:8] == `DWC_E12MP_X4NS_CR_TYPE_LANE ||
                      raddr[10:8] == `DWC_E12MP_X4NS_CR_TYPE_RAW_PCS_LANE) ? cr_chan_addr : 4'h0;  

assign cr_reg_req     = reg_req;
assign cr_reg_wr_en   = reg_wr_en & reg_req;
assign cr_reg_rd_en   = reg_rd_en & reg_req;
assign cr_reg_addr    = {1'b0,raddr[10:8],chan_field[3:0],raddr[7:0]};
assign cr_reg_wr_data = wr_data;

// ---------------------------------------------------------------------
// %%CREG FSM_OVRD_CTL - FSM override control register
//   OFFSET: 0x0
//   ATTR: READ,WRITE
//   FIELDS:
//     [14] FSM_OVRD_EN     - Enable overriding the FSM execution of commands
//          NOTES:            Must be asserted to use FSM_CMD_START and FSM_JMP_EN features
//          RESET: 0x0
//     [13] FSM_CMD_START   - Start executing the new command
//          NOTES:            This is a self-clearing bit
//          RESET: 0x0
//     [12] FSM_JMP_EN      - Force the FSM to jump to FSM_JMP_ADDR in the program memory
//          NOTES:            Is applied when FSM_CMD_START is pulsed.
//          RESET: 0x0
//   [11:0] FSM_JMP_ADDR    - The jump address used when FSM_JUMP_EN=1
//          NOTES:            The address is encoded as follows: [11:8] mem_lane, [7:5] bank, [4:0] register
//          RESET: 0x0
//
// ---------------------------------------------------------------------
wire [15:0] cr_ovrd_ctl_rd_data;
dwc_e12mp_phy_x4_ns_cr_rw_reg #(.WIDTH(15), .RST_VAL({`DWC_FW_OVRD_INIT_VAL,14'b0_0_000000000000}), .MSK_VAL(15'b0_1_0_000000000000)) 
 ovrd_ctl_reg (
  .cr_val      ({
                 fsm_ovrd_en_r,
                 fsm_cmd_start_r,
                 fsm_jmp_en_r,
                 fsm_jmp_addr_r
                 }),
  .cr_rd_data  (cr_ovrd_ctl_rd_data),
  .cr_wr_data  (cr_wr_data),
  .cr_wr_en    (cr_wr_en),
  .cr_clk      (cr_clk),
  .cr_rst      (cr_rst),
  .cr_sel      (cr_sel[0]),
  .cr_self_clr (fsm_cmd_start_r)
);

// -------------------------------------------------------------------------
// %%CREG MEM_ADDR_MON - Memory Address Monitor
//   OFFSET: 0x1
//   ATTR: READ
//   FIELDS:
//    [15:0] MEM_ADDR    - Current value of memory address used in Lane FSM
// -------------------------------------------------------------------------
wire [15:0] cr_mem_addr_rd_data;
dwc_e12mp_phy_x4_ns_cr_r_reg #(.WIDTH(16)) mem_addr_reg (
  .cr_rd_data (cr_mem_addr_rd_data),
  .cr_sel     (cr_sel[1]),
  .cr_val     ({
                cr_mem_addr[15:0]
                })
);

// -------------------------------------------------------------------------
// %%CREG STATUS_MON - FSM Status Monitor
//   OFFSET: 0x2
//   ATTR: READ
//   FIELDS:
//      [10] RDMSK_DISABLED  - Check if read mask is currently disabled (i.e. mask is all ones)
//       [9] WRMSK_DISABLED  - Check if write mask is currently disabled (i.e. mask is all ones)
//       [8] WAIT_CNT_EQ0    - Check if wait counter currently equals zero
//       [7] ALU_RES_EQ0     - Check if ALU result register currently equals zero
//       [6] ALU_OVFLW       - Current value of ALU overflow bit
//       [5] CMD_RDY         - New command is ready for execution (applicable when FSM_OVRD_EN=1)
//     [4:0] STATE           - Current state of Lane FSM
// -------------------------------------------------------------------------
wire [15:0] cr_status_rd_data;
dwc_e12mp_phy_x4_ns_cr_r_reg #(.WIDTH(11)) status_reg (
  .cr_rd_data (cr_status_rd_data),
  .cr_sel     (cr_sel[2]),
  .cr_val     ({
                 rdmsk_disabled,
                 wrmsk_disabled,
                 wait_cnt_eq0,
                 alures_eq0,
                 alures[16],
                 cmd_rdy,
                 curr_state[4:0]
                })
);

// ---------------------------------------------------------------------
// %%CREG FAST_RX_STARTUP_CAL - Status of Fast RX Start Up Calibration
//   OFFSET: 0x3
//   ATTR: READ
//   FIELDS:
//      [0] FAST_RX_STARTUP_CAL - Status of fast RX start-up calibration
// ---------------------------------------------------------------------
wire [15:0] cr_rx_fast_startup_cal_rd_data;
dwc_e12mp_phy_x4_ns_cr_r_reg #(.WIDTH(1)) rx_fast_startup_cal_reg (
  .cr_rd_data  (cr_rx_fast_startup_cal_rd_data),
  .cr_sel      (cr_sel[3]),
  .cr_val      ({
                 rx_fast_startup_cal_r
                 })
);

// ---------------------------------------------------------------------
// %%CREG FAST_RX_ADAPT - Status of Fast RX Adaptation
//   OFFSET: 0x4
//   ATTR: READ
//   FIELDS:
//      [0] FAST_RX_ADAPT - Status of fast RX adaptation
// ---------------------------------------------------------------------
wire [15:0] cr_rx_fast_adapt_rd_data;
dwc_e12mp_phy_x4_ns_cr_r_reg #(.WIDTH(1)) rx_fast_adapt_reg (
  .cr_rd_data  (cr_rx_fast_adapt_rd_data),
  .cr_sel      (cr_sel[4]),
  .cr_val      ({
                 rx_fast_adapt_r
                 })
);

// ---------------------------------------------------------------------
// %%CREG FAST_RX_AFE_CAL - Status of Fast RX AFE Calibration
//   OFFSET: 0x5
//   ATTR: READ
//   FIELDS:
//      [0] FAST_RX_AFE_CAL    - Status of fast RX AFE DAC start-up calibration
// ---------------------------------------------------------------------
wire [15:0] cr_rx_fast_afe_cal_rd_data;
dwc_e12mp_phy_x4_ns_cr_r_reg #(.WIDTH(1)) rx_fast_afe_cal_reg (
  .cr_rd_data  (cr_rx_fast_afe_cal_rd_data),
  .cr_sel      (cr_sel[5]),
  .cr_val      ({
                 rx_fast_afe_cal_r
                 })
);

// ---------------------------------------------------------------------
// %%CREG FAST_RX_DFE_CAL - Status of Fast RX DFE Calibration
//   OFFSET: 0x6
//   ATTR: READ
//   FIELDS:
//      [0] FAST_RX_DFE_CAL    - Status of fast RX DFE slicer start-up calibration
// ---------------------------------------------------------------------
wire [15:0] cr_rx_fast_dfe_cal_rd_data;
dwc_e12mp_phy_x4_ns_cr_r_reg #(.WIDTH(1)) rx_fast_dfe_cal_reg (
  .cr_rd_data  (cr_rx_fast_dfe_cal_rd_data),
  .cr_sel      (cr_sel[6]),
  .cr_val      ({
                 rx_fast_dfe_cal_r
                 })
);

// ---------------------------------------------------------------------
// %%CREG FAST_RX_BYPASS_CAL - Status of Fast RX BYPASS Calibration
//   OFFSET: 0x7
//   ATTR: READ
//   FIELDS:
//      [0] FAST_RX_BYPASS_CAL - Status of fast RX Bypass slicer start-up calibration
// ---------------------------------------------------------------------
wire [15:0] cr_rx_fast_bypass_cal_rd_data;
dwc_e12mp_phy_x4_ns_cr_r_reg #(.WIDTH(1)) rx_fast_bypass_cal_reg (
  .cr_rd_data  (cr_rx_fast_bypass_cal_rd_data),
  .cr_sel      (cr_sel[7]),
  .cr_val      ({
                 rx_fast_bypass_cal_r
                 })
);

// ---------------------------------------------------------------------
// %%CREG FAST_RX_REFLVL_CAL - Status of Fast RX Reference Level Calibration
//   OFFSET: 0x8
//   ATTR: READ
//   FIELDS:
//      [0] FAST_RX_REFLVL_CAL - Status of fast RX reference level (100mv, 125mv, 150mv) start-up calibration
// ---------------------------------------------------------------------
wire [15:0] cr_rx_fast_reflvl_cal_rd_data;
dwc_e12mp_phy_x4_ns_cr_r_reg #(.WIDTH(1)) rx_fast_reflvl_cal_reg (
  .cr_rd_data  (cr_rx_fast_reflvl_cal_rd_data),
  .cr_sel      (cr_sel[8]),
  .cr_val      ({
                 rx_fast_reflvl_cal_r
                 })
);

// ---------------------------------------------------------------------
// %%CREG FAST_RX_IQ_CAL - Status of Fast RX IQ Calibration
//   OFFSET: 0x9
//   ATTR: READ
//   FIELDS:
//      [0] FAST_RX_IQ_CAL    - Status of fast RX IQ start-up calibration
// ---------------------------------------------------------------------
wire [15:0] cr_rx_fast_iq_cal_rd_data;
dwc_e12mp_phy_x4_ns_cr_r_reg #(.WIDTH(1)) rx_fast_iq_cal_reg (
  .cr_rd_data  (cr_rx_fast_iq_cal_rd_data),
  .cr_sel      (cr_sel[9]),
  .cr_val      ({
                 rx_fast_iq_cal_r
                 })
);

// ---------------------------------------------------------------------
// %%CREG FAST_RX_AFE_ADAPT - Status of Fast RX AFE Adaptation
//   OFFSET: 0xA
//   ATTR: READ
//   FIELDS:
//      [0] FAST_RX_AFE_ADAPT  - Status of fast RX AFE DAC start-up adaptation
// ---------------------------------------------------------------------
wire [15:0] cr_rx_fast_afe_adapt_rd_data;
dwc_e12mp_phy_x4_ns_cr_r_reg #(.WIDTH(1)) rx_fast_afe_adapt_reg (
  .cr_rd_data  (cr_rx_fast_afe_adapt_rd_data),
  .cr_sel      (cr_sel[10]),
  .cr_val      ({
                 rx_fast_afe_adapt_r
                 })
);

// ---------------------------------------------------------------------
// %%CREG FAST_RX_DFE_ADAPT - Status of Fast RX DFE Adaptation
//   OFFSET: 0xB
//   ATTR: READ
//   FIELDS:
//      [0] FAST_RX_DFE_ADAPT  - Status of fast RX DFE DAC start-up adaptation
// ---------------------------------------------------------------------
wire [15:0] cr_rx_fast_dfe_adapt_rd_data;
dwc_e12mp_phy_x4_ns_cr_r_reg #(.WIDTH(1)) rx_fast_dfe_adapt_reg (
  .cr_rd_data  (cr_rx_fast_dfe_adapt_rd_data),
  .cr_sel      (cr_sel[11]),
  .cr_val      ({
                 rx_fast_dfe_adapt_r
                 })
);

// ---------------------------------------------------------------------
// %%CREG FAST_SUP - Status of Fast Support block
//   OFFSET: 0xC
//   ATTR: READ
//   FIELDS:
//      [0] FAST_SUP  - Status of fast Support block (MPLL and Rtune)
// ---------------------------------------------------------------------
wire [15:0] cr_tx_fast_sup_rd_data;
dwc_e12mp_phy_x4_ns_cr_r_reg #(.WIDTH(1)) tx_fast_sup_reg (
  .cr_rd_data  (cr_tx_fast_sup_rd_data),
  .cr_sel      (cr_sel[12]),
  .cr_val      ({
                 tx_fast_sup_r
                 })
);

// ---------------------------------------------------------------------
// %%CREG FAST_TX_CMN_MODE - Status of Fast TX Common-mode Charge-up
//   OFFSET: 0xD
//   ATTR: READ
//   FIELDS:
//      [0] FAST_TX_CMN_MODE - Status of fast TX Common-mode Charge-up
// ---------------------------------------------------------------------
wire [15:0] cr_tx_fast_cmn_mode_rd_data;
dwc_e12mp_phy_x4_ns_cr_r_reg #(.WIDTH(1)) tx_fast_cmn_mode_reg (
  .cr_rd_data  (cr_tx_fast_cmn_mode_rd_data),
  .cr_sel      (cr_sel[13]),
  .cr_val      ({
                 tx_fast_cmn_mode_r
                 })
);

// ---------------------------------------------------------------------
// %%CREG FAST_TX_RXDET - Status of Fast TX detect RX
//   OFFSET: 0xE
//   ATTR: READ
//   FIELDS:
//      [0] FAST_TX_RXDET - Status of fast TX detect RX
// ---------------------------------------------------------------------
wire [15:0] cr_tx_fast_rxdet_rd_data;
dwc_e12mp_phy_x4_ns_cr_r_reg #(.WIDTH(1)) tx_fast_rxdet_reg (
  .cr_rd_data  (cr_tx_fast_rxdet_rd_data),
  .cr_sel      (cr_sel[14]),
  .cr_val      ({
                 tx_fast_rxdet_r
                 })
);

// ---------------------------------------------------------------------
// %%CREG FAST_RX_PWRUP - Status of Fast RX Power-up
//   OFFSET: 0xF
//   ATTR: READ
//   FIELDS:
//      [0] FAST_RX_PWRUP  - Status of fast RX Power-up (LOS, VREG/AFE and DCC)
// ---------------------------------------------------------------------
wire [15:0] cr_rx_fast_pwrup_rd_data;
dwc_e12mp_phy_x4_ns_cr_r_reg #(.WIDTH(1)) rx_fast_pwrup_reg (
  .cr_rd_data  (cr_rx_fast_pwrup_rd_data),
  .cr_sel      (cr_sel[15]),
  .cr_val      ({
                 rx_fast_pwrup_r
                 })
);

// ---------------------------------------------------------------------
// %%CREG FAST_RX_VCO_WAIT - Status of Fast RX VCO Wait Times
//   OFFSET: 0x10
//   ATTR: READ
//   FIELDS:
//      [0] FAST_RX_VCO_WAIT  - Status of fast RX VCO wait times
// ---------------------------------------------------------------------
wire [15:0] cr_rx_fast_vco_wait_rd_data;
dwc_e12mp_phy_x4_ns_cr_r_reg #(.WIDTH(1)) rx_fast_vco_wait_reg (
  .cr_rd_data  (cr_rx_fast_vco_wait_rd_data),
  .cr_sel      (cr_sel[16]),
  .cr_val      ({
                 rx_fast_vco_wait_r
                 })
);

// ---------------------------------------------------------------------
// %%CREG FAST_RX_VCO_CAL - Status of Fast RX VCO Calibration
//   OFFSET: 0x11
//   ATTR: READ
//   FIELDS:
//      [0] FAST_RX_VCO_CAL  - Status of fast RX VCO Calibration
// ---------------------------------------------------------------------
wire [15:0] cr_rx_fast_vco_cal_rd_data;
dwc_e12mp_phy_x4_ns_cr_r_reg #(.WIDTH(1)) rx_fast_vco_cal_reg (
  .cr_rd_data  (cr_rx_fast_vco_cal_rd_data),
  .cr_sel      (cr_sel[17]),
  .cr_val      ({
                 rx_fast_vco_cal_r
                 })
);

// ---------------------------------------------------------------------
// %%CREG CMNCAL_STATUS - Status of common calibration initiation
//   OFFSET: 0x12
//   ATTR: READ
//   FIELDS:
//      [1] CMNCAL_DONE    - Indicates whether common calibration (mpll and rtune)
//          NOTES:           has been completed by any lane or not.
//      [0] CMNCAL_INIT    - Indicates whether common calibration (mpll and rtune)
//          NOTES:           has been started by any lane or not.
// ---------------------------------------------------------------------
wire [15:0] cr_cmncal_sts_rd_data;
dwc_e12mp_phy_x4_ns_cr_r_reg #(.WIDTH(2)) cmncal_sts_reg (
  .cr_rd_data  (cr_cmncal_sts_rd_data),
  .cr_sel      (cr_sel[18]),
  .cr_val      ({
                 lanes_cmncal_done,
                 lanes_cmncal_init
                 })
);

// ---------------------------------------------------------------------
// %%CREG FAST_RX_CONT_CAL_ADAPT - Status of Fast RX Continuous Calibration/Adaptation
//   OFFSET: 0x13
//   ATTR: READ
//   FIELDS:
//      [0] FAST_RX_CONT_CAL_ADAPT - Status of fast RX continuous calibration/adaptation
// ---------------------------------------------------------------------
wire [15:0] cr_rx_fast_cont_cal_adapt_rd_data;
dwc_e12mp_phy_x4_ns_cr_r_reg #(.WIDTH(1)) rx_fast_cont_cal_adapt_reg (
  .cr_rd_data  (cr_rx_fast_cont_cal_adapt_rd_data),
  .cr_sel      (cr_sel[19]),
  .cr_val      ({
                 rx_fast_cont_cal_adapt_r
                 })
);

// ---------------------------------------------------------------------
// %%CREG FAST_RX_CONT_ADAPT - Status of Fast RX Continuous Adaptation
//   OFFSET: 0x14
//   ATTR: READ
//   FIELDS:
//      [0] FAST_RX_CONT_ADAPT - Status of fast RX continuous adaptation
// ---------------------------------------------------------------------
wire [15:0] cr_rx_fast_cont_adapt_rd_data;
dwc_e12mp_phy_x4_ns_cr_r_reg #(.WIDTH(1)) rx_fast_cont_adapt_reg (
  .cr_rd_data  (cr_rx_fast_cont_adapt_rd_data),
  .cr_sel      (cr_sel[20]),
  .cr_val      ({
                 rx_fast_cont_adapt_r
                 })
);

// ---------------------------------------------------------------------
// %%CREG FAST_RX_CONT_DATA_CAL - Status of Fast RX Continuous Data Calibration
//   OFFSET: 0x15
//   ATTR: READ
//   FIELDS:
//      [0] FAST_RX_CONT_DATA_CAL - Status of fast RX continuous data calibration
// ---------------------------------------------------------------------
wire [15:0] cr_rx_fast_cont_data_cal_rd_data;
dwc_e12mp_phy_x4_ns_cr_r_reg #(.WIDTH(1)) rx_fast_cont_data_cal_reg (
  .cr_rd_data  (cr_rx_fast_cont_data_cal_rd_data),
  .cr_sel      (cr_sel[21]),
  .cr_val      ({
                 rx_fast_cont_data_cal_r
                 })
);

// ---------------------------------------------------------------------
// %%CREG FAST_RX_CONT_PHASE_CAL - Status of Fast RX Continuous Phase Calibration
//   OFFSET: 0x16
//   ATTR: READ
//   FIELDS:
//      [0] FAST_RX_CONT_PHASE_CAL - Status of fast RX continuous phase calibration
// ---------------------------------------------------------------------
wire [15:0] cr_rx_fast_cont_phase_cal_rd_data;
dwc_e12mp_phy_x4_ns_cr_r_reg #(.WIDTH(1)) rx_fast_cont_phase_cal_reg (
  .cr_rd_data  (cr_rx_fast_cont_phase_cal_rd_data),
  .cr_sel      (cr_sel[22]),
  .cr_val      ({
                 rx_fast_cont_phase_cal_r
                 })
);

// ---------------------------------------------------------------------
// %%CREG FAST_RX_CONT_AFE_CAL - Status of Fast RX Continuous AFE Calibration
//   OFFSET: 0x17
//   ATTR: READ
//   FIELDS:
//      [0] FAST_RX_CONT_AFE_CAL - Status of fast RX continuous AFE calibration
// ---------------------------------------------------------------------
wire [15:0] cr_rx_fast_cont_afe_cal_rd_data;
dwc_e12mp_phy_x4_ns_cr_r_reg #(.WIDTH(1)) rx_fast_cont_afe_cal_reg (
  .cr_rd_data  (cr_rx_fast_cont_afe_cal_rd_data),
  .cr_sel      (cr_sel[23]),
  .cr_val      ({
                 rx_fast_cont_afe_cal_r
                 })
);

// ---------------------------------------------------------------------
// %%CREG FAST_RX_FLAGS_RSVD_0 - Status of Fast RX Flags RSVD 0
//   OFFSET: 0x18
//   ATTR: READ
//   FIELDS:
//      [0] FAST_RX_FLAGS_RSVD_0 - Reserved
// ---------------------------------------------------------------------
wire [15:0] cr_rx_fast_flags_rsvd_0_rd_data;
dwc_e12mp_phy_x4_ns_cr_r_reg #(.WIDTH(1)) rx_fast_flags_rsvd_0_reg (
  .cr_rd_data  (cr_rx_fast_flags_rsvd_0_rd_data),
  .cr_sel      (cr_sel[24]),
  .cr_val      ({
                 rx_fast_flags_rsvd_r[0]
                 })
);

// ---------------------------------------------------------------------
// %%CREG FAST_RX_FLAGS_RSVD_1 - Status of Fast RX Flags RSVD 1
//   OFFSET: 0x19
//   ATTR: READ
//   FIELDS:
//      [0] FAST_RX_FLAGS_RSVD_1 - Reserved
// ---------------------------------------------------------------------
wire [15:0] cr_rx_fast_flags_rsvd_1_rd_data;
dwc_e12mp_phy_x4_ns_cr_r_reg #(.WIDTH(1)) rx_fast_flags_rsvd_1_reg (
  .cr_rd_data  (cr_rx_fast_flags_rsvd_1_rd_data),
  .cr_sel      (cr_sel[25]),
  .cr_val      ({
                 rx_fast_flags_rsvd_r[1]
                 })
);

// ---------------------------------------------------------------------
// %%CREG FAST_RX_FLAGS_RSVD_2 - Status of Fast RX Flags RSVD 2
//   OFFSET: 0x1A
//   ATTR: READ
//   FIELDS:
//      [0] FAST_RX_FLAGS_RSVD_2 - Reserved
// ---------------------------------------------------------------------
wire [15:0] cr_rx_fast_flags_rsvd_2_rd_data;
dwc_e12mp_phy_x4_ns_cr_r_reg #(.WIDTH(1)) rx_fast_flags_rsvd_2_reg (
  .cr_rd_data  (cr_rx_fast_flags_rsvd_2_rd_data),
  .cr_sel      (cr_sel[26]),
  .cr_val      ({
                 rx_fast_flags_rsvd_r[2]
                 })
);

// ---------------------------------------------------------------------
// %%CREG FAST_RX_FLAGS_RSVD_3 - Status of Fast RX Flags RSVD 3
//   OFFSET: 0x1B
//   ATTR: READ
//   FIELDS:
//      [0] FAST_RX_FLAGS_RSVD_3 - Reserved
// ---------------------------------------------------------------------
wire [15:0] cr_rx_fast_flags_rsvd_3_rd_data;
dwc_e12mp_phy_x4_ns_cr_r_reg #(.WIDTH(1)) rx_fast_flags_rsvd_3_reg (
  .cr_rd_data  (cr_rx_fast_flags_rsvd_3_rd_data),
  .cr_sel      (cr_sel[27]),
  .cr_val      ({
                 rx_fast_flags_rsvd_r[3]
                 })
);

// ---------------------------------------------------------------------
// %%CREG FAST_RX_FLAGS_RSVD_4 - Status of Fast RX Flags RSVD 4
//   OFFSET: 0x1C
//   ATTR: READ
//   FIELDS:
//      [0] FAST_RX_FLAGS_RSVD_4 - Reserved
// ---------------------------------------------------------------------
wire [15:0] cr_rx_fast_flags_rsvd_4_rd_data;
dwc_e12mp_phy_x4_ns_cr_r_reg #(.WIDTH(1)) rx_fast_flags_rsvd_4_reg (
  .cr_rd_data  (cr_rx_fast_flags_rsvd_4_rd_data),
  .cr_sel      (cr_sel[28]),
  .cr_val      ({
                 rx_fast_flags_rsvd_r[4]
                 })
);

// ---------------------------------------------------------------------
// %%CREG FAST_RX_FLAGS_RSVD_5 - Status of Fast RX Flags RSVD 5
//   OFFSET: 0x1D
//   ATTR: READ
//   FIELDS:
//      [0] FAST_RX_FLAGS_RSVD_5 - Reserved
// ---------------------------------------------------------------------
wire [15:0] cr_rx_fast_flags_rsvd_5_rd_data;
dwc_e12mp_phy_x4_ns_cr_r_reg #(.WIDTH(1)) rx_fast_flags_rsvd_5_reg (
  .cr_rd_data  (cr_rx_fast_flags_rsvd_5_rd_data),
  .cr_sel      (cr_sel[29]),
  .cr_val      ({
                 rx_fast_flags_rsvd_r[5]
                 })
);

// ---------------------------------------------------------------------
// %%CREG FAST_RX_FLAGS_RSVD_6 - Status of Fast RX Flags RSVD 6
//   OFFSET: 0x1E
//   ATTR: READ
//   FIELDS:
//      [0] FAST_RX_FLAGS_RSVD_6 - Reserved
// ---------------------------------------------------------------------
wire [15:0] cr_rx_fast_flags_rsvd_6_rd_data;
dwc_e12mp_phy_x4_ns_cr_r_reg #(.WIDTH(1)) rx_fast_flags_rsvd_6_reg (
  .cr_rd_data  (cr_rx_fast_flags_rsvd_6_rd_data),
  .cr_sel      (cr_sel[30]),
  .cr_val      ({
                 rx_fast_flags_rsvd_r[6]
                 })
);

// ---------------------------------------------------------------------
// %%CREG RX_IQ_PHASE_OFFSET - Offset value for IQ Phase Calculation
//   OFFSET: 0x1F
//   ATTR: READ,WRITE
//   FIELDS:
//    [4:0] RX_IQ_PHASE_OFFSET - Offset value for IQ Phase Calculation
//          RESET: 0x3
// ---------------------------------------------------------------------
wire [15:0] cr_rx_iq_phase_offset_rd_data;
dwc_e12mp_phy_x4_ns_cr_rw_reg #(.WIDTH(5), .RST_VAL(5'd3), .MSK_VAL(5'd0)) 
 rx_iq_phase_offset_reg (
  .cr_val      ({
                 rx_iq_phase_offset_r
                 }),
  .cr_rd_data  (cr_rx_iq_phase_offset_rd_data),
  .cr_wr_data  (cr_wr_data),
  .cr_wr_en    (cr_wr_en),
  .cr_clk      (cr_clk),
  .cr_rst      (cr_rst),
  .cr_sel      (cr_sel[31]),
  .cr_self_clr (1'b0)
);

// Muxed register read for CREG register
//     
assign cr_rd_data = cr_ovrd_ctl_rd_data |
                    cr_mem_addr_rd_data |
                    cr_status_rd_data |
                    cr_rx_fast_startup_cal_rd_data |
                    cr_rx_fast_adapt_rd_data |
                    cr_rx_fast_afe_cal_rd_data |
                    cr_rx_fast_dfe_cal_rd_data |
                    cr_rx_fast_bypass_cal_rd_data |
                    cr_rx_fast_reflvl_cal_rd_data |
                    cr_rx_fast_iq_cal_rd_data |
                    cr_rx_fast_afe_adapt_rd_data |
                    cr_rx_fast_dfe_adapt_rd_data |
                    cr_tx_fast_sup_rd_data |
                    cr_tx_fast_cmn_mode_rd_data |
                    cr_tx_fast_rxdet_rd_data |
                    cr_rx_fast_pwrup_rd_data |
                    cr_rx_fast_vco_wait_rd_data |
                    cr_rx_fast_vco_cal_rd_data |
                    cr_cmncal_sts_rd_data |
                    cr_rx_fast_cont_cal_adapt_rd_data |
                    cr_rx_fast_cont_adapt_rd_data |
                    cr_rx_fast_cont_data_cal_rd_data |
                    cr_rx_fast_cont_phase_cal_rd_data |
                    cr_rx_fast_cont_afe_cal_rd_data |
                    cr_rx_fast_flags_rsvd_0_rd_data |
                    cr_rx_fast_flags_rsvd_1_rd_data |
                    cr_rx_fast_flags_rsvd_2_rd_data |
                    cr_rx_fast_flags_rsvd_3_rd_data |
                    cr_rx_fast_flags_rsvd_4_rd_data |
                    cr_rx_fast_flags_rsvd_5_rd_data |
                    cr_rx_fast_flags_rsvd_6_rd_data |
                    cr_rx_iq_phase_offset_rd_data;
   
// ----------------------------------------------
// ASCII decode of state for debug
// ----------------------------------------------
// synopsys translate_off
reg [47:0] curr_state_asc;
always @ (curr_state)
begin
   case (curr_state)
     IDLE            :  curr_state_asc = "IDLE  ";
     CMD_FETCH       :  curr_state_asc = "CMD_FE";
     CMD_DECODE      :  curr_state_asc = "CMD_DE";
     WAIT_REG_ACK    :  curr_state_asc = "WT_RAK";
     ST_D_1          :  curr_state_asc = "ST_D1 ";
     WRMSK_1         :  curr_state_asc = "WRMSK1";
     CP_RA_1         :  curr_state_asc = "CP_RA1";
     CP_RP_1         :  curr_state_asc = "CP_RP1";
     CP_PX_1         :  curr_state_asc = "CP_PX1";
     ADD_1           :  curr_state_asc = "ADD_1 ";
     ADD_2           :  curr_state_asc = "ADD_2 ";
     STAT_START_1    :  curr_state_asc = "STRT_1";
     STAT_START_2    :  curr_state_asc = "STRT_2";
     STAT_WAIT_DN    :  curr_state_asc = "WT_DN ";
     STAT_OPR_1      :  curr_state_asc = "OPR_1 ";
     STAT_CORR_1     :  curr_state_asc = "CORR_1";
     STAT_CORR_2     :  curr_state_asc = "CORR_2";
     STAT_CORR_3     :  curr_state_asc = "CORR_3";
     STAT_CORR_4     :  curr_state_asc = "CORR_4";
     STAT_CORR_5     :  curr_state_asc = "CORR_5";
     STAT_ESL_RD     :  curr_state_asc = "ESL_RD";
     STAT_RST_MSK    :  curr_state_asc = "RSTMSK";
     STAT_CLR_ADPT_1 :  curr_state_asc = "CLRADT1";
     STAT_CLR_ADPT_2 :  curr_state_asc = "CLRADT2";
     WAIT_CNTR_1     :  curr_state_asc = "WT_CNT";
     default         :  curr_state_asc = "ERR   ";
   endcase
end
// synopsys translate_on

endmodule

